import Parser = require('./../base/Parser');
import GCJ_CLASS_TYPE = require('./../../common/GCJ_CLASS_TYPE');
import DEFINE = require('./../../common/DEFINE');
import ParaContour=require('./../../common/graph/ParaContour');
import  OnePara=require('./../../common/graph/OnePara');
import  ParaChar=require('./../../common/graph/ParaChar');
import Point=require('./../../common/graph/Point');
import FColor=require('./../color/FColor');
import ObjBase=require('./ObjBase');
import PageInfo=require('./../../common/PageInfo');
import ImageObj=require('./ImageObj');
import ObjRelativePosType=require('./../base/ObjRelativePosType');
import ObjPositionAlign=require('./../base/ObjPositionAlign');
import SJGPage=require('./../cont/SJGPage');
import SJGReplaceItemBase=require('./../replace/SJGReplaceItemBase');
import SJGReplaceGroup = require('./../replace/SJGReplaceGroup');

var path=require('path');
var CommonUtil=require('../../../../common/util/CommonUtil');
class SJGSelectRect{public static CONTROL_LEFT=3;public static CONTROL_RIGHT=1};
var async  = require( 'async'); // 同步控制
var fs = require('fs')
var CONFIG=require('../../../../common/config');
var rpcFunc=require('./../../../routes/rpcSrv/rpcFunc.js');

export  = TextObj;

/**
 *
 * @author 
 *
 */
class TextObj extends ObjBase{
    /**
    * position  1.靠左  2.居中  3.靠右  4.分散对齐
    */ 
    public static POSITION_LEFT = 1;
    public static POSITION_CENTER = 2;
    public static POSITION_RIGHT = 3;
    public static POSITION_DISPERSE = 4;
    
    /**
    * verticle position  1.靠上  2.居中  3.靠下 
    */
    public static V_POSITION_TOP=1;
    public static V_POSITION_CENTER=2;
    public static V_POSITION_BOTTOM=3;
    
    /**
     * text type: 0:普通正文; 1:小标题
     */
    public static TEXT_TYPE_NORMAL = 0;
    public static TEXT_TYPE_HEADLINE = 1;
    
    /**
    * bold/italic  0.常规  1.粗体  2.斜体  3.粗斜体
    */
    public static BI_NORMAL = 0;
    public static BI_BOLD = 1;
    public static BI_ITALIC = 2;
    public static BI_BOLD_ITALIC = 3;
    /**
     * textDirection文字方向：0 横排、1 竖排
     */
    public static TEXT_DIRECTION_HORIZON = 0;
    public static TEXT_DIRECTION_VERTICLE = 1;
    /**
     * 头尾预留的宽度
     */
    public static HEAD_WIDTH: number=0; // 左侧预留的宽度
    public static  TAIL_WIDTH: number=0; // 右侧预留的宽度
    
    /**
     * 放大倍数:文字过小时，图片服务会显示偏差，需要先放大
     */ 
    public static FONT_ZOOM_FACTOR: number=64;
    
    /**
     * font-zoom,放大倍数:文字过小时，图片服务会显示偏差，需要先放大
     */
    public fz=1;
    
    
    
    /**
     * font-name，字体
     */
    public fn: string="微软雅黑";
    /**
     * font-size，字号
     */ 
    public fs = 20;
    /**
     * bold/italic  0.常规  1.粗体  2.斜体  3.粗斜体
     */ 
    public bi: number = TextObj.BI_NORMAL;
    /**
     * position  1.靠左  2.居中  3.靠右  4.分散对齐
     */ 
    public po: number = TextObj.POSITION_LEFT;
    /**
     * verticle-position  1.靠上  2.居中  3.靠下 
     */
    public vpo: number=TextObj.V_POSITION_TOP;
    /**
     * char space，字间距
     */ 
    public cs:number = 6;
    /**
     * line space，行间距
     */ 
    public ls:number = 10;
    /*
     * TEXT
     */ 
    public te:string = "";
    /**
     * 默认横排
     */ 
    public td = TextObj.TEXT_DIRECTION_HORIZON;
    /**
     * 字轮廓
     */ 
    public pc = new ParaContour();
    /**
     * 实际每行字符数[此属性不参与序列化]
     */ 
    public lineCnt: Array<number> = new Array<number>();
    public lineEnd: Array<number> = new Array<number>();
    
    
    // 文字独有属性
    public min: number=0;          // 最小字数
    public max: number=30;         // 最大字数
    
    /**
     * 文字类型：正文/小标题。注意：此属性仅仅在“编组”中才有效
     * 注意：此参数需要逐渐废弃，小标题作为属性出现在TextObj2中
     */ 
    public tt: number = TextObj.TEXT_TYPE_NORMAL;
    
    /**
     * 文字抬头：例如图标。注意：不影响文字本身的尺寸
     */ 
    public head: ObjBase=null;
    /**
    *  文字抬头／小标题的位置 0.无  1.在文字左边  2.在文字上边  2.在文字右边  2.在文字下边  
    */
    public static HP_NONE   =0;
    public static HP_LEFT   =1;
    public static HP_TOP     =2;
    public static HP_RIGHT  =3;
    public static HP_BOTTOM=4;
    public hp: number   =   TextObj.HP_LEFT; // head position
    /**
     * 文字抬头离文字的距离
     */
    public hd: number=20; // head distance
    
    public constructor(g?) {
        super(g);
        
        this.ct= GCJ_CLASS_TYPE.CLASS_TYPE_TextObj;
	}
	
    // 从json对象(注意不是json字符串)中解析
    // 参数：self,true表示只拷贝自身数据，而不拷贝子的数据
    public fromJson(jsonObj,versionId,self?) {
        super.fromJson(jsonObj,versionId,self);

        this.fn = jsonObj.fn;
        this.fs = jsonObj.fs;// font-size，字号
        if(jsonObj.hasOwnProperty("fz")){
            this.fz=jsonObj.fz;
        }
        this.bi = jsonObj.bi;// bold/italic 0.常规   1.粗体   2.斜体   3.粗斜体
        this.po = jsonObj.po; // position 1.靠左   2.居中   3.靠右
        if(jsonObj.hasOwnProperty("vpo")){
            this.vpo=jsonObj.vpo;
        }
        
        this.cs = jsonObj.cs; // char space，字间距
        this.ls = jsonObj.ls; // line space，行间距
        this.te = jsonObj.te; // text
        this.td = jsonObj.td; // 默认横排
        if(jsonObj.pc!=null){
            this.pc.fromJson(jsonObj.pc, versionId);
        }
        if(jsonObj.min!=null){
            this.min=jsonObj.min;
        }
        if(jsonObj.max!=null) {
            this.max=jsonObj.max;
        }
        
        // 文字类型: 正文/小标题
        if(jsonObj.hasOwnProperty("tt")) {
            this.tt = jsonObj.tt;
        }else{
            this.tt = TextObj.TEXT_TYPE_NORMAL;
        }
        
        // 文字抬头
        if(jsonObj.hasOwnProperty("head")) {
            var one: ObjBase=<ObjBase> Parser.fromUnknownJson(jsonObj.head,versionId,this.getGlobalData());
            if(one) { 
                this.head=one;
                one.parent=this;// 建立子对父的引用
            }else{
                this.head=null;
            }
        }
        if(jsonObj.hasOwnProperty("hp")) {
            this.hp=jsonObj.hp;
        }
        if(jsonObj.hasOwnProperty("hd")) {
            this.hd=jsonObj.hd;
        }
        
               
        // 加载文档时
        if (this.getGlobalData().docStatus() == DEFINE.DOC_STATUS_LOADING) {
            this.getGlobalData().objManager().saveObject( this );
        }      
    }
    // 转成json字符串
    public toJson(): string {
        // 去掉父json字符串的头尾
        var superJson = super.toJson();
        superJson = superJson.substr(1,superJson.length - 2);

        var ret = '{';
        ret += superJson;
                                
        // fn
        ret += ',';
        ret += '"fn":' + '"';
        ret += this.fn + '"';
                    
        // fs
        ret += ',';
        ret += '"fs":';
        ret += this.fs;   
        
        // fz
        ret+=',';
        ret+='"fz":';
        ret+=this.fz; 
           
        // bi
        ret += ',';
        ret += '"bi":';
        ret += this.bi; 
            
        // po
        ret += ',';
        ret += '"po":';
        ret += this.po; 
        
        // vpo
        ret+=',';
        ret+='"vpo":';
        ret+=this.vpo; 
            
        // cs
        ret += ',';
        ret += '"cs":';
        ret += this.cs; 
           
        // ls
        ret += ',';
        ret += '"ls":';
        ret += this.ls; 
            
        // te
        ret+=',';
        ret+='"te":'+'"';
        ret+=this.te.replace(/"/g,'\\\"')+'"';// 处理引号引起的问题
            
        // td
        ret += ',';
        ret += '"td":';
        ret += this.td; 
            
        // pc
        ret += ',';
        ret += '"pc":';
        ret += this.pc.toJson();
        
        // min
        ret+=',';
        ret+='"min":';
        ret+=this.min; 
        
        // max
        ret+=',';
        ret+='"max":';
        ret+=this.max; 
        
        // type
        ret += ',';
        ret += '"tt":';
        ret += this.tt; 
        
        // head
        if(this.head){
            ret+=',';
            ret+='"head":';
            ret+=this.head.toJson();            
        }
        if(this.hp){
            ret+=',';
            ret+='"hp":';
            ret+=this.hp;             
        }
        if(this.hd) {
            ret+=',';
            ret+='"hd":';
            ret+=this.hd;
        }
        

        ret += '}';

        return ret;
    }
    // 获取行高
    public getLineH(): number {
        var lh: number = 60;
        // TODO
        // fn(this.fs) 根据字号计算
        return lh;
    }
    // 将文字排到一行上，并且限定宽度，如果超过宽度，则缩放文字
    public refreshToOneLineAndFixWidth() { 
        var newLen = this.refreshToOneLine();
        var ratio: number=this.pos.w/newLen;
        if(ratio<1.0){
            // 缩放字号、字间距、行间距
            this.fs*=ratio;
            this.cs*=ratio;
            this.ls*=ratio;
            // 缩放每个字的轮廓
            this.pc.adjustPosition(ratio,ratio,2);            
        }
        
        // 刷新水平对齐和垂直对齐方式
        this.refreshToAlignType();
        this.refreshToVerticleAlignType(0);

        this.adjustHeadByPosition();// 调整抬头
    }
    // 将文字排到一行上
    private refreshToOneLine(){
        // 遍历轮廓中的每个字，从左向右放
        var lineH: number=this.fs;
        var lineW: number=this.pos.w;
        
        var curX: number=TextObj.HEAD_WIDTH;
        for(var i in this.pc.paras) {

            var onePara: OnePara=this.pc.paras[i];
            for(var j in onePara.chars) {
                var oneChar: ParaChar=onePara.chars[j];
                // 如果超出边界，新起一行
                curX+=oneChar.w/this.fz;
                oneChar.bx=curX-oneChar.w/this.fz;
                oneChar.by=lineH*(TextObj.Y_FACTOR)+this.ls;
                oneChar.line=0;
                
                // 加上字间距
                curX+=this.cs;
            }
        }
        
        
        // 更新高度
        var newH: number=lineH+2*this.ls;
        var oldH: number=this.pos.h
        this.pos.h=newH;
        
        return curX;
    }
    
    // 重置各字符bx、by，以及各段高宽
    public refresh(replace: SJGReplaceGroup=null) {
        
        
        var minus:number = this.refreshAlignLeft();
        this.refreshToAlignType();
        this.refreshToVerticleAlignType(minus);
        
        this.adjustHeadByPosition();// 调整抬头
    }
    // 按左对齐排列
    // 返回：文字的高与文字轮廓的高的差值
    public static Y_FACTOR: number=4/5;
    private refreshAlignLeft():number{
        // 遍历轮廓中的每个字，从左向右放，直到碰到this.pos.w为止
        var lineH: number=this.fs;
        var lineW: number=this.pos.w;
        var line: number=0; // 行数
        var curX: number=TextObj.HEAD_WIDTH;
        for(var i in this.pc.paras){
            if(i>0){// 新段落新起一行
                line++;
                curX=TextObj.HEAD_WIDTH;
            }
            
            var onePara: OnePara=this.pc.paras[i];
            for(var j in onePara.chars){
                var oneChar: ParaChar=onePara.chars[j];
                // 如果超出边界，新起一行
                curX+=oneChar.w/this.fz;
                if(curX>(lineW-TextObj.TAIL_WIDTH)) {
                    line++;
                    curX=TextObj.HEAD_WIDTH+oneChar.w/this.fz;
                }
                oneChar.bx=curX-oneChar.w/this.fz;
                oneChar.by=lineH*(line+TextObj.Y_FACTOR)+this.ls*(line+1);
                oneChar.line=line;
                
                // 加上字间距
                curX+=this.cs;
            }
        }
        // 只有新的高度大于旧的高度时，才更新
        var newH: number=(line+1)*lineH+(line+2)*this.ls;
        var oldH: number = this.pos.h
        if(newH> this.pos.h){
            this.pos.h=newH;
        }
        
        return oldH-newH;
    }
    // 垂直方向调整为正确的排列方式
    private refreshToVerticleAlignType(minus) {
        if(minus<=0) return;
        
        var vOffset: number=0;
        if(this.vpo==TextObj.V_POSITION_CENTER) {
            vOffset=minus/2;
        } else if(this.vpo==TextObj.V_POSITION_BOTTOM){ 
            vOffset=minus;
        }
        
        if(vOffset>0) { 
            for(var i in this.pc.paras) {
                var onePara: OnePara=this.pc.paras[this.pc.paras.length-1-i];// 倒着遍历
                for(var j in onePara.chars) {
                    var oneChar: ParaChar=onePara.chars[onePara.chars.length-1-j];// 倒着遍历
                    oneChar.by+=vOffset;
                }
            }
        }
    }
    // 水平方向调整为正确的排列方式
    private refreshToAlignType() { 
        var line: number=-1;
        var offset: number=0;// line对应的偏移
        if(this.po == TextObj.POSITION_RIGHT
            ||this.po == TextObj.POSITION_CENTER){
            for(var i in this.pc.paras){
                var onePara: OnePara=this.pc.paras[this.pc.paras.length-1-i];// 倒着遍历
                for(var j in onePara.chars){
                    var oneChar: ParaChar=onePara.chars[onePara.chars.length-1-j];// 倒着遍历
                    var rightest: Boolean=false;// 一行的最右侧
                    if(line==-1) {// 最后一个字
                        rightest=true;
                    } else if(oneChar.line==(line-1)){ // 换行时
                        rightest=true;
                    }
                    if(rightest){
                        line=oneChar.line;
                        offset=this.pos.w-TextObj.TAIL_WIDTH-oneChar.w/this.fz-oneChar.bx;
                        if(this.po== TextObj.POSITION_CENTER){// 居中对齐的偏移减半
                            offset=offset/2;
                        }
                    }
                    // 调整
                    oneChar.bx+=offset;
                }
            }
        }
    }
    
    // 获取对象名称
    public getObjetName(): string {
        var objNm = "文字";
        switch(this.tt) {
            case 0: objNm += " [普通正文]"; break;
            case 1: objNm += " [小标题]"; break;
        }
        if(this.head) {
            objNm+=" [抬头]";
        }
        
        // 检索所选page中的replaces，不能从map3[]取
        var selPage: SJGPage=this.getGlobalData().selectManager().getPageOfSelect();
        var t=selPage.isTitleOrSubTitle(this.id);
        if(SJGReplaceItemBase.TYPE_PAGE_TITLE==t) {
            objNm+="[页标题]";
        } else if(SJGReplaceItemBase.TYPE_PAGE_SUBTITLE==t) {
            objNm+="[页副标题]";
        }
        
        return objNm;
    }
    
    // 扩展大小
    // 参数：controlType 控制点类型
    // 参数：ratioX x缩放比例
    // 参数：ratioY y缩放比例
    // 参数：outside true表示操作所在的最外层对象，false表示内部对象
    public expand(controlType: number,ratioX: number,ratioY: number,outside: boolean) {
        super.expand(controlType,ratioX,ratioY,outside);

//        if(SJGSelectRect.CONTROL_LEFT==controlType
//            ||SJGSelectRect.CONTROL_RIGHT==controlType) { 
        if(this.constrain.scale==1) {
            this.refresh();
        }
//        }
        
    }
    
    // 根据指定宽度调整字符的换行（居左换行）
    // limitWidth 为null时，只按段落换行
    public chgLineWithWidth(limitWidth: number = null): void {
        // 限定宽度
        var limitW: number = limitWidth;
        // 固定行高
        var LH: number = this.fs;

        // 记录实际每行字符数
        this.lineCnt.splice(0);
        this.lineEnd.splice(0);
        if (this.pc && this.pc.paras && this.pc.paras.length > 0) {
            
            // 循环段
            var charIndex = 0;
            var lineNum: number = 0;// 行数
            var lineCharCnt: number = 0;// 每行文字数
            var maxW: number = 0;// 全文最大宽度
            for (var i = 0;i < this.pc.paras.length;i++) {
                var para: OnePara = this.pc.paras[i];
                lineNum++;// 每一段换行
                lineCharCnt = 0;
                    
                // 循环文字
                var tmpW: number = 0;// 一行的宽度累加
                var maxTmpW: number = 0;// 一段文字段最大宽度
                for (var n = 0;n < para.chars.length;n++) {
                    var char: ParaChar = para.chars[n];
                    lineCharCnt++;

                    if (0 == n) {
                        char.bx = 0;
                        tmpW = char.w;
                    } else {
                        char.bx = tmpW + this.cs;
                        tmpW += (char.w + this.cs);
                    }

                    if (limitW != null && limitW > 0) {
                        if (n > 0 && tmpW > limitW) {// 超过宽度换行
                            lineCharCnt--;
                            this.lineCnt.push(lineCharCnt);
                            this.lineEnd.push(charIndex);
                            
                            lineNum++;
                            lineCharCnt = 1;
                            char.bx = 0;
                            tmpW = char.w;
                        }
                    }

                    char.by = (LH + this.ls) * lineNum - this.ls;

                    maxTmpW = (tmpW > maxTmpW) ? tmpW : maxTmpW;
                    charIndex++;
                }
                
                this.lineCnt.push(lineCharCnt);
                this.lineEnd.push(charIndex);

                para.h = LH * lineNum;// 段高
                para.w = maxTmpW;// 段宽
                    
                maxW = (maxTmpW > maxW) ? maxTmpW : maxW;
            }

            this.pc.h = (LH + this.ls) * lineNum - this.ls;// 全文高
            this.pc.w = maxW;// 全文宽

        } else {
            this.pc.w = 0;
            this.pc.h = 0;
        }
    }
    
    // 缩放对象
    public scale(s: number) {
        super.scale(s);
        this.fz*=s;
        
        if(this.head) {
            this.head.scale(s);
        }
    }
    
    // 取得第index个字的轮廓
    public getParaChar(index: number):ParaChar {
        if(this.pc.paras.length==0) return null;
        if(this.pc.paras[0].chars.length<=index) return null;
        return this.pc.paras[0].chars[index];
    }
    // 取得第idnex个字的y中心（相对于TextObj对象）
    public getParaChatCenterY(index:number):number{
        var char: ParaChar=this.getParaChar(index);
        if(!char) return 0;
        
        var fzCenerY=char.centerY();
        var centerY = fzCenerY/this.fz + char.by;
        return centerY;
        
        
    }
    
    // 修正head的位置，使其作为文字的子
    public adjustHeadByPosition(){
        if(!this.head){
            return;
        }
        
        if(this.hp==TextObj.HP_LEFT) {
            // 左侧
            this.head.pos.x=-this.hd-this.head.pos.w;
            // 让y受文字的“垂直对齐”方式控制
            // 如果文字“垂直方向向上对齐”，则抬头的y中心对齐到首行文字的y中心
            if(this.vpo==TextObj.V_POSITION_TOP) {
                // 取得第一个字的y中心（相对于TextObj的坐标）
                var centerY = this.getParaChatCenterY(0);
                this.head.pos.y=centerY-this.head.pos.h/2;
            }
            
            // 如果文字“垂直方向居中对齐”，则抬头的y中心对齐到所有行文字的y中心
            else if(this.vpo==TextObj.V_POSITION_CENTER){ 
                this.head.pos.y = this.pos.h/2-this.head.pos.h/2
            }
            // 如果文字“垂直方向向下对齐”，则抬头的y中心对齐到尾行文字的y中心
            else if(this.vpo==TextObj.V_POSITION_BOTTOM) {
                var centerY=this.getParaChatCenterY(this.te.length-1);
                this.head.pos.y=centerY-this.head.pos.h/2;
            }
            
            
        } else if(this.hp==TextObj.HP_TOP) {
            // 上侧
            this.head.pos.y=-this.hd-this.head.pos.h;
            // 让x受文字的“水平对齐”方式控制
            // 如果文字“水平方向向左对齐”，则抬头的x左侧对齐到TextObj左侧
            if(this.po==TextObj.POSITION_LEFT) { 
                this.head.pos.x=0;
            }
            // 如果文字“水平方向居中对齐”，则抬头的x中心对齐到TextObj的x中心
            else if(this.po==TextObj.POSITION_CENTER){
                this.head.pos.x=this.pos.w/2-this.head.pos.w/2;
            }
            // 如果文字“水平方向向右对齐”，则抬头的x右侧对齐到TextObj的x右侧
            else if(this.po==TextObj.POSITION_RIGHT) {
                this.head.pos.x=this.pos.w-this.head.pos.w;
            }
            
        } else if(this.hp==TextObj.HP_RIGHT) {
            // 右侧
            this.head.pos.x=this.hd+this.pos.w;
            // 让y受文字的“垂直对齐”方式控制
            // 如果文字“垂直方向向上对齐”，则抬头的y中心对齐到首行文字的y中心
            if(this.vpo==TextObj.V_POSITION_TOP) {
                // 取得第一个字的y中心（相对于TextObj的坐标）
                var centerY=this.getParaChatCenterY(0);
                this.head.pos.y=centerY-this.head.pos.h/2;
            }
            
            // 如果文字“垂直方向居中对齐”，则抬头的y中心对齐到所有行文字的y中心
            else if(this.vpo==TextObj.V_POSITION_CENTER) {
                this.head.pos.y=this.pos.h/2-this.head.pos.h/2
            }
            // 如果文字“垂直方向向下对齐”，则抬头的y中心对齐到尾行文字的y中心
            else if(this.vpo==TextObj.V_POSITION_BOTTOM) {
                var centerY=this.getParaChatCenterY(this.te.length-1);
                this.head.pos.y=centerY-this.head.pos.h/2;
            }
        } else {
            // 下侧
            this.head.pos.y=this.hd+this.pos.h;
            // 让x受文字的“水平对齐”方式控制
            // 如果文字“水平方向向左对齐”，则抬头的x左侧对齐到TextObj左侧
            if(this.po==TextObj.POSITION_LEFT) {
                this.head.pos.x=0;
            }
            // 如果文字“水平方向居中对齐”，则抬头的x中心对齐到TextObj的x中心
            else if(this.po==TextObj.POSITION_CENTER) {
                this.head.pos.x=this.pos.w/2-this.head.pos.w/2;
            }
            // 如果文字“水平方向向右对齐”，则抬头的x右侧对齐到TextObj的x右侧
            else if(this.po==TextObj.POSITION_RIGHT) {
                this.head.pos.x=this.pos.w-this.head.pos.w;
            }

        } 
    }
    
    // 添加子对象，能够添加子对象的对象重载
    // 参数：child 待添加的字对象
    // 参数：insertIndex 待添加的位置
    // 参数：flag 操作flag， flag==1 表示添加为文字抬头
    public addChild(child: ObjBase,insertIndex: number,flag: number=0): boolean {
        if(flag==1){
            this.removeChild(child.id);
            this.head=child;
            child.parent=this;
        }
        
        return true;
    }
    // 删除子对象，能够添加子对象的对象重载
    public removeChild(id: number) {
        if(this.head && this.head.id==id){
            this.head.parent=null;
            this.head=null;
        }
    }
    
    // 深度更新id［处理自身和子对象，递归］
    // 参数：idMaps，新旧id的对应关系, 例如：[{oldId:1,newId:2}]
    public deepResetId(idMaps: Array<any>) {
        super.deepResetId(idMaps);
        
        if(this.head){
            this.head.deepResetId(idMaps);
        }
    }

//SJG_MARK_APPEND--------------------


}//SJG_MARK_END-------------------------